package com.uft.controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Future;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.uft.model.dao.*;
import com.uft.model.entity.Audit;
import com.uft.model.entity.Preferences;
import com.uft.model.entity.Profile;
import com.uft.model.entity.Server;
import com.uft.model.entity.ServerSettings;
import com.uft.model.entity.Users;
import com.uft.remote.UftRemote;
import com.uft.security.tam.utils.AutoLoginFilter;
import com.uft.service.DeployService;
import com.uft.service.TaskTracker;
import com.uft.service.WasService;
import com.uft.utils.UftUtils;
import com.uft.security.tam.utils.*;

@Controller
public class ServerController {
	 @Autowired
	 private ProfileDAO profileDAO;
	 @Autowired
	 private ServerDAO serverDAO;	
	 @Autowired
	 private DeployService deployService;
	 @Autowired
	 private WasService wasService;
	 @Autowired
	 private  AuditDAO auditDAO;
	 @Autowired
	 private UsersDAO usersDAO;
	 @Autowired
	 private PreferencesDAO prefDAO;
	 @Autowired
	 private  TaskTracker taskTracker;
	 private  static Logger  logger = Logger.getLogger(ServerController.class);
	@RequestMapping(value="/getServerList", method = RequestMethod.POST)
	@ResponseBody
	public String getServerList(@RequestParam(value="serverName", required=false) String serverName,
			@RequestParam(value="nodeName", required=false) String nodeName,
			@RequestParam(value="jtStartIndex", required=false, defaultValue="0") int jtStartIndex,
			@RequestParam(value="jtPageSize", required=false, defaultValue="20") int jtPageSize,
			HttpServletRequest request) {
		String result="";
		boolean tamEnabled=false;
		List<Server> serverList=new ArrayList<Server>();
		List<Server> cleanedServerList = new ArrayList<Server>();
		try{
			//int count=serverDAO.getServerCount();
			if(serverName != null || nodeName != null ){
				logger.debug("ServerName: "+serverName+" nodeName: "+nodeName);
				serverList=serverDAO.getServerByNameNode(serverName, nodeName,jtStartIndex,jtPageSize);
			}
			else{
				serverList=serverDAO.getAllServers(jtStartIndex,jtPageSize);
			}
			String groupStr="";
			//logger.debug("Headers: "+request.getHeaderNames());
			Enumeration  enames = request.getHeaderNames();
			while (enames.hasMoreElements()) {
				String name = (String) enames.nextElement();
				String value = request.getHeader(name);
				logger.debug("Header Name: "+name+" value: "+value);
			}
			
			if(request.getHeader(AutoLoginFilter.principalUserRequestHeader) != null && 
						!request.getHeader(AutoLoginFilter.principalUserRequestHeader).equalsIgnoreCase("")){
				groupStr=request.getHeader(AutoLoginFilter.principalGroupRequestHeader);	
			}else{
				Users user=usersDAO.getUserByName("TEST");
				groupStr=user.getGroups();
			}
			
			String patternStr= null;
			Preferences pref=prefDAO.getPreferencesByName(UftUtils.RESTART_GROUP_PATTERN_PREF_NAME);
			if(pref != null){
				patternStr= pref.getPrefValue();
			}
			
			String suffix  = null;
			String prefix = null;
			Preferences suffixPref=prefDAO.getPreferencesByName(UftUtils.SERVER_PREF_SUFFIX);
			if(suffixPref != null){
				suffix=suffixPref.getPrefValue();
			}
			Preferences prefixPref=prefDAO.getPreferencesByName(UftUtils.SERVER_PREF_PREFIX);
			if(prefixPref != null){
				prefix=prefixPref.getPrefValue();
			}
			
			
			if(!groupStr.equalsIgnoreCase("")){
				List<String> groups= UftUtils.parseRestartGroups(groupStr, patternStr);
				for(Server s:serverList){
					logger.debug("serverName: "+s.getServerName());
					String sName=s.getServerName();
					String appName=UftUtils.getApplicationName(sName, suffix, prefix);
					logger.debug("application Name: "+appName);
					if(UftUtils.matchApplicationName(sName, groups)){
						logger.debug("Match Found:  authorized..."+sName);
						cleanedServerList.add(s);
					}
					
				}
			}
    		ObjectMapper mapper = new ObjectMapper();
			String listData=mapper.writeValueAsString(cleanedServerList);
			logger.info("List dat: "+listData);
			result="{\"Result\":\"OK\",\"Records\":"+listData+",\"TotalRecordCount\":"+serverList.size()+"}";
		}
		catch(Exception ex){
			result="{\"Result\":\"ERROR\",\"Message\":\""+ex.getMessage()+"\"}";
			ex.printStackTrace();
		}
		logger.debug(result);
		return result;
	 }
	@RequestMapping(value="/searchServerList", method = RequestMethod.GET)
	@ResponseBody
	public String searchServerName(@RequestParam(value="term", required=true) String searchString,
			@RequestParam(value="name", required=true) String name,
			HttpServletRequest request) {
		String result="";
		List<String> serverList=new ArrayList<String>();
		List<HashMap<String, String>> serversArray=new ArrayList<HashMap<String,String>>();
		try{
			if(name.equalsIgnoreCase("serverName")){
				serverList =serverDAO.searchServerByServerName(searchString);
			}
			if(name.equalsIgnoreCase("nodeName")){
				serverList =serverDAO.searchServerByNodeName(searchString);
			}
			if(name.equalsIgnoreCase("serverHostname")){
				serverList =serverDAO.searchServerByServerHostname(searchString);
			}
			
			for(String s: serverList){
				HashMap<String, String> temp= new HashMap<String,String>();
					temp.put("label", s);
					temp.put("value", s);
				    serversArray.add(temp);
			}
			ObjectMapper mapper = new ObjectMapper();
			String listData=mapper.writeValueAsString(serversArray);
			
			logger.debug("List dat: "+listData);
			result=listData;
		}
		catch(Exception ex){
			result="{error}";
			ex.printStackTrace();
		}
		
		return result;
	 }
	@RequestMapping(value="/getDeployOptions", method = RequestMethod.POST)
	@ResponseBody
	public String getDeployOptions(@RequestParam("serverId") int serverId,HttpServletRequest request){
		String result="{";
		logger.debug("get Deploy Options");
		Profile profile= profileDAO.getProfileByServerId(serverId);
		Server server=serverDAO.getServerById(serverId);
		result+="\"serverId\":\""+server.getServerId()+"\"";
		result+=", \"serverName\":\""+server.getServerName()+"\"";
		result+=", \"region\":\""+profile.getRegion()+"\"";
		result+=", \"dmgrName\":\""+profile.getProfileName()+"\"";
		result+=", \"dmgrHost\":\""+profile.getHostname()+"\"";
		List<String> deployFiles= deployService.getDeployFiles(String.valueOf(serverId));
		List<String> deployTempFiles=new ArrayList<String>();
		for(String str: deployFiles){
			deployTempFiles.add("\""+str+"\"");
		}
		deployFiles=deployTempFiles;
		if(deployFiles.size() > 1){
			String deployString =", \"deployFile\":";
			deployString+="[";
			String tempStr=StringUtils.join(deployFiles, ",");
			deployString+=tempStr;
			deployString+="]";
			result+=deployString;
		}
		result+="}";
		logger.debug(result);
		return result;
	}
	
	@RequestMapping(value="/getDeployStatus", method = RequestMethod.POST)
	@ResponseBody
	public String getDeployStatus(@RequestParam("serverId") String serverId,HttpServletRequest request){
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		String result="{";
		HashMap<String, String> statusMap=deployService.getDeploymentStatusAll(serverId);
		if(statusMap.get("status").equalsIgnoreCase("RUNNING")){
			result+="\"Result\":\"RUNNING\"";
			result+=", \"Output\":\""+StringEscapeUtils.escapeEcmaScript(statusMap.get("output")) +"\"";
			result+=", \"Error\":\""+StringEscapeUtils.escapeEcmaScript(statusMap.get("error")) +"\"";
			result+=", \"Code\":\""+statusMap.get("code") +"\"";
			result+=", \"StartTime\":\""+StringEscapeUtils.escapeEcmaScript(statusMap.get("startTime")) +"\"";
			result+=", \"EndTime\":\""+StringEscapeUtils.escapeEcmaScript(statusMap.get("endTime")) +"\"";
		}else if(statusMap.get("status").equalsIgnoreCase("STOPPED")){
			result+="\"Result\":\"STOPPED\"";
			result+=", \"Output\":\""+StringEscapeUtils.escapeEcmaScript(statusMap.get("output")) +"\"";
			result+=", \"Error\":\""+StringEscapeUtils.escapeEcmaScript(statusMap.get("error")) +"\"";
			result+=", \"Code\":\""+statusMap.get("code") +"\"";
			result+=", \"StartTime\":\""+StringEscapeUtils.escapeEcmaScript(statusMap.get("startTime")) +"\"";
			result+=", \"EndTime\":\""+StringEscapeUtils.escapeEcmaScript(statusMap.get("endTime") )+"\"";
			deployService.clearDeployment(serverId);
			if(!statusMap.get("startTime").equalsIgnoreCase("") && !statusMap.get("endTime").equalsIgnoreCase("")){
				auditDAO.addAudit(new Audit(auth.getName(),Integer.valueOf(serverId),"DeployTask",statusMap.get("startTime").toString(),statusMap.get("endTime"),"END"));
			}
			
		}else{
			result+="\"Result\":\"N/A\"";
		}
		
		result+="}";
		logger.debug(result);
		return result;
	}
	@RequestMapping(value="/addDeploymentTask", method = RequestMethod.POST)
	@ResponseBody
	public String addDeploymentTask(@RequestParam(value="serverId", required=true) String serverId,
			@RequestParam(value="email", required=false) String email,
			@RequestParam(value="deployFile", required=false) String deployFile,
			@RequestParam(value="autoRestart", required=false) boolean autoRestart,
			HttpServletRequest request){
		String result="";
		logger.debug("Add Deployment Task: "+serverId);
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		HashMap<String, String> options= new HashMap<String, String>();
		if(email != null && !email.equalsIgnoreCase("")){
			options.put("email", email);
		}
		if(deployFile != null && !deployFile.equalsIgnoreCase("")){
			options.put("deployFile", deployFile);
		}
		options.put("autoRestart", String.valueOf(autoRestart));
		logger.info(options);
		if( deployService.addDeploymentTask(serverId,options)){
			auditDAO.addAudit(new Audit(auth.getName(),Integer.valueOf(serverId),"DeployTask",Calendar.getInstance().getTime().toString(),"",options.toString()));
			result="{\"Result\":\"OK\"}";
		}else{
			result="{\"Result\":\"ERROR\",\"Message\":\"ERROR\"}";
			
		}
		logger.info(result);
		return result;
	}
	@RequestMapping(value="/startServer", method = RequestMethod.POST)
	@ResponseBody
	public String startServer(@RequestParam(value="serverId", required=true) String serverId,HttpServletRequest request){
		String result="";
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		logger.info("Starting Server : "+serverId+ " By username: "+auth.getName());
		try{
			int profileId= profileDAO.getProfileIdByServerId(Integer.parseInt(serverId));
			String uniqueId= "START|"+profileId+"|"+serverId;
			auditDAO.addAudit(new Audit(auth.getName(),Integer.valueOf(serverId),"startServer",Calendar.getInstance().getTime().toString(),"","Server Started issued"));
			String r=startServer(String.valueOf(profileId), serverId);
			result="{\"Result\":\"OK\",\"Message\":\""+r+"\",\"UniqueId\":\""+uniqueId+"\"}";
		}catch(Exception e){
			result="{\"Result\":\"ERROR\",\"Message\":\""+e.getMessage()+"\"}";
		}
		
		return result;
	}
	@RequestMapping(value="/stopServer", method = RequestMethod.POST)
	@ResponseBody
	public String stopServer(@RequestParam(value="serverId", required=true) String serverId,HttpServletRequest request){
		String result="";
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		logger.info("Starting Server : "+serverId+ " By username: "+auth.getName());
		try{
			int profileId= profileDAO.getProfileIdByServerId(Integer.parseInt(serverId));
			String uniqueId= "STOP|"+profileId+"|"+serverId;
			auditDAO.addAudit(new Audit(auth.getName(),Integer.valueOf(serverId),"stopServer",Calendar.getInstance().getTime().toString(),"","Server Stop issued"));
			String r=stopServer(String.valueOf(profileId), serverId);
			result="{\"Result\":\"OK\",\"Message\":\""+r+"\",\"UniqueId\":\""+uniqueId+"\"}";
		}catch(Exception e){
			result="{\"Result\":\"ERROR\",\"Message\":\""+e.getMessage()+"\"}";
		}
		return result;
	}
	@RequestMapping(value="/serverStatus", method = RequestMethod.POST)
	@ResponseBody
	public String serverStatus(@RequestParam(value="serverId", required=true) String serverId,HttpServletRequest request){
		String result="";
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		logger.info(" Server Status : "+serverId+ " By username: "+auth.getName());
		try{
			int profileId= profileDAO.getProfileIdByServerId(Integer.parseInt(serverId));
			String r=wasService.serverStatus(String.valueOf(profileId), serverId);
			
			result="{\"Result\":\"OK\",\"Message\":\""+r+"\"}";
		}catch(Exception e){
			result="{\"Result\":\"ERROR\",\"Message\":\""+e.getMessage()+"\"}";
		}
		return result;
	}
	
	
	
	@RequestMapping(value="/getServerInfoView", method = RequestMethod.GET)
	public ModelAndView getServerInfoView(@RequestParam(value="serverId", required=true) String serverId, HttpServletRequest request,  
            HttpServletResponse response){
		ModelAndView model = new ModelAndView("serverInfo");
		Server server=serverDAO.getServerById(Integer.parseInt(serverId));
		if(server != null){
			int profileId= profileDAO.getProfileIdByServerId(server.getServerId());
			com.uft.was.config.Xml configXml;		
			try {			
				configXml = wasService.getRuntimeConfig(String.valueOf(profileId), server.getNodeName(), server.getServerName(),"");
				model.addObject("server", server);
				model.addObject("configXml", configXml);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		logger.debug("Get Server Info View");
		return model;
	}
	@RequestMapping(value="/getServerListView", method = RequestMethod.GET)
	public ModelAndView getServerListView(HttpServletRequest request,  
            HttpServletResponse response){
		ModelAndView model = new ModelAndView("serverList");
		logger.debug("getServerListView");
		//Server server=serverDAO.getServerById(Integer.parseInt(serverId));
		//model.addObject("server", server);		
		return model;
	}
	

	@RequestMapping(value="/getServer", method = RequestMethod.POST)
	@ResponseBody
	public String getServer(@RequestParam(value="serverId", required=true) String serverId, HttpServletRequest request,  
            HttpServletResponse response){
		String result="";
		try{
			Server server=serverDAO.getServerById(Integer.parseInt(serverId));
			ObjectMapper mapper = new ObjectMapper();
			String listData=mapper.writeValueAsString(server);
			result="{\"Result\":\"OK\",\"Record\":"+listData+"}";
		}catch(Exception ex){
			result="{\"Result\":\"ERROR\",\"Message\":\""+ex.getMessage()+"\"}";
			ex.printStackTrace();
			
		}
		logger.debug(result);
		
			
		return result;
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value="/getServerSettingsView", method = RequestMethod.GET)
	public ModelAndView getServerSettingsView(@RequestParam(value="serverId", required=true) String serverId, HttpServletRequest request,  
            HttpServletResponse response){
		ModelAndView model = new ModelAndView("serverSetting");
		Server server=serverDAO.getServerById(Integer.parseInt(serverId));
		ServerSettings serverSetting=server.getServerSettings();
		model.addObject("server", server);
		model.addObject("serverSetting", serverSetting);		
		return model;
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value="/updateServerSetting", method = RequestMethod.POST)
	@ResponseBody
	public String updateServerSetting(ServerSettings serverSettings,HttpServletRequest request){
		String result="";
		try{
			
			logger.debug("profilePref: "+serverSettings.getId());
			
			serverDAO.updateServerSetting(serverSettings);
			result="{\"Result\":\"OK\"}";
		}catch(Exception ex){
			result="{\"Result\":\"ERROR\",\"Message\":\""+ex.getMessage()+"\"}";
			ex.printStackTrace();
			
		}
		logger.debug(result);
		return result;
	}
	
	
	
	@RequestMapping(value="/getDeployViewPage", method = RequestMethod.GET)
	public ModelAndView getDeployViewPage(@RequestParam(value="serverId", required=true) String serverId, HttpServletRequest request,  
            HttpServletResponse response){
		ModelAndView model = new ModelAndView("serverDeploy");
		Profile profile= profileDAO.getProfileByServerId(Integer.parseInt(serverId));
		Server server=serverDAO.getServerById(Integer.parseInt(serverId));
		model.addObject("profile", profile);  
		model.addObject("server", server);
		List<String> deployFiles= deployService.getDeployFiles(serverId);
		logger.debug("List of Deploy File for ServerId: "+serverId+" Size: "+deployFiles.size());
		model.addObject("deployFiles",deployFiles);
		return model;
	}
	
	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@RequestMapping(value="/updateServerLists", method = RequestMethod.POST)
	@ResponseBody
	public String updateServerLists(@RequestParam("profileId") String profileId,HttpServletRequest request){
		String result="";
		try{
		  	logger.debug("profile id : "+profileId);
		  	String uniqueId= "UPDATE|"+profileId+"|"+profileId;
			String r=updateServerListTask(profileId);
			result="{\"Result\":\"OK\",\"Message\":\""+r+"\",\"UniqueId\":\""+uniqueId+"\"}";
			 
		}catch(Exception ex){
			result="{\"Result\":\"ERROR\",\"Message\":\""+ex.getMessage()+"\"}";
			ex.printStackTrace();
			
		}
		logger.debug(result);
		return result;
	}
	
	public String startServer(String profileId, String serverId){
		String uniqueId="START|"+profileId+"|"+serverId;
		logger.info("Adding a server Start Task for Id: "+serverId);
		logger.debug(uniqueId);
		String result="";
		if(taskTracker.checkTaskExits(uniqueId)){
			logger.info("Task Id: "+uniqueId +" already running");
			result="Another Task is running";
			
		}else{
			logger.info("Scheduling a start Server Task: ");
			Future<Object> future= wasService.addStartServerTask(profileId, serverId);
			logger.info("Addin a future task");
			taskTracker.addTask(uniqueId, future);
			result="scheduled";
		}
		logger.debug(result);
		return result;
	}
	public String stopServer(String profileId, String serverId){
		String uniqueId="STOP|"+profileId+"|"+serverId;
		logger.info("Adding a server Stop Task for Id: "+serverId);
		logger.debug(uniqueId);
		String result="";
		if(taskTracker.checkTaskExits(uniqueId)){
			logger.info("Task Id: "+uniqueId +" already running");
			result="Another Task is running";
		}else{
			logger.info("Scheduling a Stop Server Task: ");
			Future<Object> future= wasService.addStopServerTask(profileId, serverId);
			logger.info("Addin a future task");
			taskTracker.addTask(uniqueId, future);
			
			result="scheduled";
		}
		
		return result;
	}
	public String updateServerListTask(String profileId){
		String uniqueId="UPDATE|"+profileId+"|"+profileId;
		String result="";
		if(taskTracker.checkTaskExits(uniqueId)){
			result="Another update Task running";
		}else{
			Future<Object> future= wasService.updateServerList(profileId);
			taskTracker.addTask(uniqueId, future);
			result="scheduled";
		}
		return result;
	}
	
	public String getStartServerTaskStatus(String profileId, String serverId){
		String uniqueId="START:"+profileId+":"+serverId;
		String result="";
		if(taskTracker.checkTaskExits(uniqueId)){
			if(taskTracker.checkTaskStatus(uniqueId).equalsIgnoreCase(UftUtils.TASK_COMPLETE)){
					result= (String) taskTracker.getOutput(uniqueId);
					return result;
			}
			if(taskTracker.checkTaskStatus(uniqueId).equalsIgnoreCase(UftUtils.TASK_RUNNING)){
				return UftUtils.TASK_RUNNING;
			}
		}else{
			return UftUtils.TASK_NOT_RUNNING;
		}
		
		return result;
	}

	@RequestMapping(value="/testServerSSHConnection", method = RequestMethod.POST)
	@ResponseBody
	public String testServerSSHConnection(@RequestParam("hostname") String hostname,
			@RequestParam("username") String username,
			@RequestParam("password") String password,
			HttpServletRequest request){
		String result="";
		try{
		  	
		  	 UftRemote uftRemote= new UftRemote(hostname,username, password, 22);  	 
			 if( uftRemote.testSSHConnection()){
				 result="{\"Result\":\"OK\"}";
			 }else{
				 result="{\"Result\":\"ERROR\",\"Message\":\"Error in Connecting...\"}";
			 }
			   
		}catch(Exception ex){
			result="{\"Result\":\"ERROR\",\"Message\":\""+ex.getMessage()+"\"}";
			ex.printStackTrace();
			
		}
		logger.debug(result);
		return result;
		
	}
	
	
}
